/* eslint-disable prefer-const */
/* eslint-disable no-prototype-builtins */
/* eslint-disable no-unsafe-optional-chaining */
import { ElMessageBox, ElMessage } from "element-plus";

/*
 * @Author: 睡衣船长 121771372@qq.com
 * @Date: 2023-09-06 14:49:52
 * @LastEditors: Mr.wangxf 2712638312@qq.com
 * @LastEditTime: 2023-11-06 14:02:35
 * @Description:  通用函数合集
 */
export function _deepClone(obj: any) {
  if (obj === null) return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  if (typeof obj !== "object") return obj;
  const cloneObj: any = new obj.constructor();
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 实现一个递归拷贝
      cloneObj[key] = _deepClone(obj[key]);
    }
  }
  return cloneObj;
}

/**
 * @name: 2712638312@qq.com
 * @desc: 获取云Static文件的图
 * @param {* String } name 图片名称
 */
export function _getImg(title: string): string {
  if (title) {
    return (
      "https://choudianbao.oss-cn-shanghai.aliyuncs.com/Admin_V1/static/" +
      title
    );
  } else {
    return "";
  }
}

/**
 * @name: 2712638312@qq.com
 * @desc: 格式化时间
 * @param {* any  } date
 * @param {* string } fmt
 * @return {* Date  }  yyyy-MM-dd hh:mm:ss
 */
export function _formatDate(date: any, fmt = "yyyy-MM-dd hh:mm:ss") {
  // TODO: date值还需要做校验，比如  NaN-aN-aN aN:aN:aN
  if (!date || date == null) return date;
  if (typeof date === "string") {
    date = new Date(date);
  }
  const o: any = {
    "M+": date.getMonth() + 1, // 月份
    "d+": date.getDate(), // 日
    "h+": date.getHours(), // 小时
    "m+": date.getMinutes(), // 分
    "s+": date.getSeconds(), // 秒
    "q+": Math.floor((date.getMonth() + 3) / 3), // 季度
    S: date.getMilliseconds(), // 毫秒
  };
  if (/(y+)/.test(fmt))
    fmt = fmt.replace(
      RegExp.$1,
      (date.getFullYear() + "").substr(4 - RegExp.$1.length)
    );
  for (const k in o) {
    if (new RegExp("(" + k + ")").test(fmt))
      fmt = fmt.replace(
        RegExp.$1,
        RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
      );
  }
  return fmt;
}

/**
 * @author: 睡衣船长
 * @description: 获取两个日期差天数
 * @param {Date} dateArray
 * @return {*}
 */
export const _diffDays = (dateArray: Date[] | string[]): number => {
  if (!dateArray || dateArray.length < 2) return 0;
  const _dateArray = _deepClone(dateArray);
  if (typeof _dateArray[0] == "string") {
    _dateArray[0] = new Date(_dateArray[0]);
  }
  if (typeof _dateArray[1] == "string") {
    _dateArray[1] = new Date(_dateArray[1]);
  }
  let day: number = Math.ceil(
    Math.abs(
      (_dateArray[0].getTime() - _dateArray[1].getTime()) / (1000 * 3600 * 24)
    )
  );
  return Number(day.toFixed(0));
};

/**
 * @name: 2712638312@qq.com
 * @desc: 获取页面最大的index层级值
 */
export function _getPageMaxZIndex(): number {
  const _zIndex: Array<Element> = [...document.body?.querySelectorAll("*")];
  const _indexNum: number =
    _zIndex.reduce(
      (r: any, e: any) => Math.max(r, +window.getComputedStyle(e).zIndex || 0),
      0
    ) + 1;
  return _indexNum;
}

/**
 * @Author: 2712638312@qq.com
 * @description: 拖拽函数
 * @param {DOM} el DOM
 * @param {any} binding 指令属性 Class
 * @param {Array<string>} binding.value.dragList 校验拖拽区域 Class，不传默认都可拖拽
 * @param {any} vnode 虚拟Dom
 */
export function _dragFun(el: HTMLElement, binding: any): void | undefined {
  // 拖拽绑定元素
  const _dragDom: HTMLElement = el;
  // 点击拖拽元素
  _dragDom.onmousedown = (event: any) => {
    // 点击的元素class
    const className: string = event?.target?.className?.indexOf
      ? event.target.className
      : "";
    // 校验拖拽区域，不传默认都可拖拽
    const dragList: Array<string> =
      binding?.value?.dragList && binding?.value?.dragList.length >= 1
        ? binding.value.dragList
        : [];
    if (
      !binding?.value?.dragList ||
      dragList.some((item: any) => {
        return className.indexOf(item) != -1;
      })
    ) {
      // 获取鼠标在元素中的位置 视图鼠标坐标 - 元素中心坐标
      const mouseX = event.clientX - _dragDom.offsetLeft;
      const mouseY = event.clientY - _dragDom.offsetTop;

      // 绑定移动和停止函数
      document.onmousemove = (e) => {
        const left: number = e.clientX - mouseX;
        const top: number = e.clientY - mouseY;
        if (binding?.value?.setStyleFun) {
          binding.value.setStyleFun(left, top);
        } else {
          _dragDom.style.position = "absolute";
          _dragDom.style.left = left + "px";
          _dragDom.style.top = top + "px";
        }
      };
      document.onmouseup = () => {
        document.onmousemove = document.onmouseup = null;
      };
    }
  };
}

/**
 * @name: yaoxueke
 * @desc: 弹出确认框
 * @param {* string } title 提示标题
 * @param {* string } con 提示内容
 * @param {* string } type 提示类型  success/warning/info/error
 * @param {* string } customClass 自定义消息框的class类名
 * @param {* string } cancelButtonText 取消按钮的文本内容
 * @param {* string } confirmButtonText 确定按钮的文本内容
 * @param {* string } cancelButtonClass 取消按钮的自定义类名
 * @param {* string } confirmButtonClass 确定按钮的自定义类名
 * @param {* string } center 是否居中布局
 * @param {* string } roundButton 按钮是否使用圆角
 */
export async function _msgBoxFun(params: any, type = "confirm"): Promise<any> {
  try {
    let res = "";
    if (type == "confirm") {
      res = await ElMessageBox.confirm(params.con || "", params.title, {
        customClass: params.customClass,
        confirmButtonText: params.confirmButtonText,
        cancelButtonText: params.cancelButtonText,
        cancelButtonClass: params.cancelButtonClass,
        confirmButtonClass: params.confirmButtonClass,
        dangerouslyUseHTMLString: !!params?.dangerouslyUseHTMLString,
        showCancelButton: params?.showCancelButton
          ? params.showCancelButton
          : true,
        showConfirmButton: params?.showConfirmButton
          ? params.showConfirmButton
          : true,
        type: params.type,
        center: params.center,
        buttonSize: "default",
        draggable: true,
        roundButton: params.roundButton,
      });
    }
    if (type == "prompt") {
      res = await ElMessageBox.prompt(params.con || "", params.title, {
        customClass: params.customClass,
        confirmButtonText: params.confirmButtonText,
        cancelButtonText: params.cancelButtonText,
        inputErrorMessage: params.inputErrorMessage,
        inputPlaceholder: params.inputPlaceholder,
        inputPattern: params.inputPattern,
        inputValidator: params.inputValidator,
        draggable: true,
        inputValue: params.inputValue,
      });
    }
    return Promise.resolve(res);
  } catch (e) {
    return Promise.reject(e);
  }
}

/**
 * @name: 2712638312@qq.com
 * @desc: 弹出提示框
 * @param {* string } message 提示内容
 * @param {* string } type 提示类型  success/warning/info/error
 * @param {* string } customClass 自定义消息框的class类名
 * @param {* string } center 是否居中布局
 * @param {* string } showClose 是否显示删除按钮
 */
export async function _msgFun(data: any): Promise<any> {
  const height: number =
    (window.innerHeight ||
      document.documentElement.clientHeight ||
      document.body.clientHeight) / 2;
  try {
    ElMessage.closeAll();
    let params: Bus_OtherKey = {};
    if (_canString(data)) {
      params.message = data;
    } else {
      params = data;
    }
    // eslint-disable-next-line new-cap
    let res = await ElMessage({
      type: params.type || "success",
      message: params.message || "",
      dangerouslyUseHTMLString: !!params?.dangerouslyUseHTMLString,
      customClass: params.customClass || "",
      duration: params.duration || 2000,
      showClose: params.showClose || false,
      center: params.center || false,
      onClose: params.onClose,
      offset: params.offset || height,
      grouping: params.grouping || false,
      repeatNum: params.repeatNum || 1,
    });
    return Promise.resolve(res);
  } catch (e) {
    return Promise.reject(e);
  }
}

/**
 * @description 判断参数是否是对象
 * @param value
 * @returns 布尔值
 */
export const _canObject = (value: any): boolean => {
  return (
    value != null &&
    typeof value === "object" &&
    JSON.stringify(value) != "{}" &&
    Object.prototype.toString.call(value) == "[object Object]"
  );
};

/**
 * @description 判断参数是否是数组
 * @param value
 * @returns 布尔值
 */
export const _canArray = (value: any): boolean => {
  return value != null && Array.isArray(value) && value.length > 0;
};

/**
 * @description 判断参数是否是boolean
 * @param value
 * @returns 布尔值
 */
export const _canBoolean = (value: any): boolean => {
  return typeof value === "boolean";
};

/**
 * @description 判断参数是否是字符串
 * @param value
 * @returns 布尔值
 */
export const _canString = (value: any): boolean => {
  return typeof value === "string" && !!value;
};

/**
 * @name: 2712638312@qq.com
 * @desc: 函数可解析一个字符串，并返回一个浮点数，
 * @param {* number | string } parameter 位值
 * @param {* number } digit 位数
 */
export function _setFormatNumber(
  parameter: number | string,
  digit: number = 2
): number | string {
  const _newParameter: string =
    typeof parameter === "number" ? String(parameter) : parameter;
  const _data: string = parseFloat(_newParameter).toFixed(digit);
  if (_data) {
    return _data;
  }
  return "";
}

/**
 * @name: 2712638312@qq.com
 * @desc: 浮点数加法运算
 * @param {*} arg1
 * @param {*} arg2
 */
export const _floatAdd = (arg1: any, arg2: any) => {
  let r1, r2, m;
  try {
    r1 = arg1.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  m = Math.pow(10, Math.max(r1, r2));
  return (arg1 * m + arg2 * m) / m;
};

/**
 * @name: 2712638312@qq.com
 * @desc: 浮点数减法运算
 * @param {*} arg1
 * @param {*} arg2
 */
export const _accSub = (arg1: any, arg2: any) => {
  let r1, r2, m, n;
  try {
    r1 = arg1.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  m = Math.pow(10, Math.max(r1, r2));
  n = r1 >= r2 ? r1 : r2;
  return parseFloat(((arg1 * m - arg2 * m) / m).toFixed(n));
};

/**
 * @description 判断参数存在链接
 * @param value
 * @returns 布尔值
 */
export const _httpFilter = (valueStr: any): boolean => {
  if (valueStr != "" && valueStr != null) {
    if (
      valueStr.indexOf("www") >= 0 ||
      valueStr.indexOf("http") >= 0 ||
      valueStr.indexOf("https") >= 0
    ) {
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
};

/**
 * @name: 2712638312@qq.com
 * @desc: 随机生成字符串
 * @param {* number  } len 位值
 */
export function _setRandomString(len: number): string {
  // 默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1
  const _chars: string = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz123456789";
  const _maxPos: number = _chars.length;
  let _pwd: string = "";
  for (let i: number = 0; i < len; i++) {
    _pwd += _chars.charAt(Math.floor(Math.random() * _maxPos));
  }
  return _pwd;
}

export const _trim = (str: string): string => {
  if (typeof str === "string" && !!str) {
    return str.replace(/(^\s*)|(\s*$)/g, "");
  }
  return str;
};

export const _trimNumber = (str: string): string => {
  if (typeof str === "string" && !!str) {
    return str.replace(/[^\d]/g, "");
  }
  return str;
};

/**
 * @author: yaoxueke
 * @description: 生成随机key值
 * @param {string} bizId  业务id  比如表单id，任务id
 * @param {string} keyType 比如select的options中的key值/checkbox中的options的key值
 * @param {string} name  选项的名称
 * @return {string}   key值
 */
export const _setRandomKey = (bizId: string, keyType: string, name: string) => {
  const timestamp = new Date().getTime(); //时间戳
  const fiveRandomArr: Array<string> = []; //生成5个随机数
  // const pinyinArr: Array<string> =
  //   HanziToPinyin.initialTreatment(name).split(""); //拼音字母数组
  const pinyinArr: Array<string> = []; //拼音字母数组
  let pinyinRadomFive: string = ""; //5个随机拼音字母
  for (let index = 0; index < 5; index++) {
    fiveRandomArr.push((Math.random() * 10).toFixed(0));
  }
  fiveRandomArr.forEach((n: string) => {
    if (pinyinArr[Number(n)]) {
      pinyinRadomFive += pinyinArr[Number(n)];
    }
  });
  const key: string = `${bizId}_${keyType}_${pinyinRadomFive}${timestamp}${(
    Math.random() * 100
  ).toFixed(0)}`;
  return key;
};

/**
 * @author: huangbowen
 * @description: 文件大小
 * @param {size} number
 * @param {size} number
 * @return {*}
 */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const _getPrintSize = (size: number, fixedNum: number = 2): string => {
  let data = "";
  if (size < 0.1 * 1024) {
    //如果小于0.1KB转化成B
    data = size.toFixed(2) + "B";
  } else if (size < 0.1 * 1024 * 1024) {
    //如果小于0.1MB转化成KB
    data = (size / 1024).toFixed(2) + "KB";
  } else if (size < 0.1 * 1024 * 1024 * 1024) {
    //如果小于0.1GB转化成MB
    data = (size / (1024 * 1024)).toFixed(2) + "MB";
  } else {
    //其他转化成GB
    data = (size / (1024 * 1024 * 1024)).toFixed(2) + "GB";
  }
  let sizeStr = data + "";
  // eslint-disable-next-line no-useless-escape
  let len = sizeStr.indexOf(".");
  let dec = sizeStr.substring(len + 1, 2);
  if (dec == "00") {
    //当小数点后为00时 去掉小数部分
    return sizeStr.substring(0, len) + sizeStr.substring(len + 3, 2);
  }
  return sizeStr;
};

/**
 * @Author: 2712638312@qq.com
 * @description: 表单样式
 * @param {any} event 表单属性
 */
export function _setElFormAttr(event?: Bus_SetElFormAttr): object {
  const attrs: Bus_SetElFormAttr = event || {};
  const data: Bus_SetElFormAttr = {
    inline: false, // 行内表单模式
    labelPosition: "right", // 表单域标签的位置
    labelWidth: "150px", // 标签的长度
    labelSuffix: "", // 表单域标签的后缀
    hideRequiredAsterisk: false, // 是否显示必填字段的标签旁边的红色星号
    showMessage: true, // 是否显示校验错误信息
    inlineMessage: false, // 是否以行内形式展示校验信息
    statusIcon: false, // 是否在输入框中显示校验结果反馈图标
    validateOnRuleChange: true, // 是否在 rules 属性改变后立即触发一次验证
    size: "default", // 用于控制该表单内组件的尺寸
    disabled: false, // 是否禁用该表单内的所有组件
    isTurnFlex: false, // 是否转flex
    ...attrs,
  };
  if (attrs?.isTurnFlex) {
    data.style = `display:flex;${attrs.style}`;
  }
  return data;
}

/**
 * @name: 2712638312@qq.com
 * @desc: 字符串截取
 * @param {* string  } str 截取元素
 * @param {* number  } len 位值
 */
export function _setStringLength(str: any, len: number): string {
  const _strNew: string = typeof str !== "string" ? String(str) : str;
  if (!str) {
    return "";
  }
  if (_strNew.length <= len) {
    return _strNew;
  } else {
    const _resultStrNew = _strNew.slice(0, len - 2);
    return _resultStrNew + "...";
  }
}

/**
 * @name: 睡衣船长
 * @desc: 防抖函数
 */
export function _debounce(
  fn: { apply: (arg0: any, arg1: any[]) => void },
  t: number = 500
) {
  let timeId: any = null;
  const delay = t;
  return function (this: any, ...args: any) {
    if (timeId) {
      clearTimeout(timeId);
    }
    timeId = setTimeout(() => {
      clearTimeout(timeId);
      timeId = null;
      // eslint-disable-next-line no-invalid-this
      fn.apply(this, args);
    }, delay);
  };
}

/*
 * @name: 2712638312@qq.com
 * @desc: 金额按千位逗号分割
 * 参数：s，需要格式化的金额数值.
 * 参数：type,判断格式化后的金额是否需要小数位.
 * 返回：返回格式化后的数值字符串.
 */
export function _formatMoney(s: any, type: any = 1) {
  if (/[^0-9\\.]/.test(s)) {
    return "0";
  }
  if (s == null || s == "") {
    return "0";
  }
  s = s.toString().replace(/^(\d*)$/, "$1.");
  s = (s + "00").replace(/(\d*\.\d\d)\d*/, "$1");
  s = s.replace(".", ",");
  let re = /(\d)(\d{3},)/;
  while (re.test(s)) s = s.replace(re, "$1,$2");
  s = s.replace(/,(\d\d)$/, ".$1");
  if (type == 0) {
    // 不带小数位(默认是有小数位)
    let a = s.split(".");
    if (a[1] == "00") {
      s = a[0];
    }
  }
  return s;
}

/**
 * @author: 2712638312@qq.com
 * @description: 数字比对小于
 */
export const _numContrast = (s1: any, s2: any) => {
  if (s1 == "" || s1 == undefined || s1 == null) return false;
  if (s2 == "" || s2 == undefined || s2 == null) return false;
  let _sn = parseFloat(s1.replace(/[^\d.-]/g, ""));
  let _en = parseFloat(s2.replace(/[^\d.-]/g, ""));
  if (_sn <= _en) {
    return true;
  }
  return false;
};

/**
 * @author: yaoxueke
 * @description: 下载文件方法
 * @param {ParamsDownloadFile} params
 */
export const _downLoadFile = (params: any) => {
  fetch(params.fileUrl).then((res) =>
    res.blob().then((blob) => {
      const a = document.createElement("a");
      const url = window.URL.createObjectURL(blob);
      a.href = url;
      a.download = params.fileName;
      a.click();
      window.URL.revokeObjectURL(url);
    })
  );
};

/**
 * @author: yaoxueke
 * @description: 数值之间百分比
 * @param {number} val
 */
export const _getRangeNumber = (
  val: Bus_StringNo,
  max: Bus_StringNo = 100,
  min: Bus_StringNo = 0,
  isSuffix: boolean = false
) => {
  val = Number(val);
  min = Number(min);
  max = Number(max);
  if (val < 0) {
    return (
      (Math.abs(Math.abs(val) + min) / (max - min)) * 100 +
      (isSuffix ? "%" : "")
    );
  } else {
    return ((val - min) / (max - min)) * 100 + (isSuffix ? "%" : "");
  }
};

/**
 * @name: 睡衣船长
 * @desc: 节流函数
 * @param {*}
 * @returns {*}
 */
export function _throttle(
  fn: { apply: (arg0: any, arg1: any[]) => void },
  t: number = 500
) {
  let flag = true;
  const interval = t;
  return function (that: any, ...args: any) {
    if (flag) {
      fn.apply(that, args);
      flag = false;
      setTimeout(() => {
        flag = true;
      }, interval);
    }
  };
}

/**
 * @name: 2712638312@qq.com
 * @desc: 元素位置
 * @param {*} object DOM
 */
export const _getTagAddr = (object: HTMLElement): any => {
  let ro: DOMRect = object.getBoundingClientRect();
  let Top: Bus_StringNo = ro.top;
  let Bottom: Bus_StringNo = ro.bottom;
  let Left: Bus_StringNo = ro.left;
  let Right: Bus_StringNo = ro.right;
  let Width: Bus_StringNo = ro.width || Right - Left;
  let Height: Bus_StringNo = ro.height || Bottom - Top;
  let X: Bus_StringNo = Left + document.documentElement?.scrollLeft;
  let Y: Bus_StringNo = Top + document.documentElement?.scrollTop;
  return {
    top: Top,
    bottom: Bottom,
    left: Left,
    right: Right,
    width: Width,
    height: Height,
    x: X,
    y: Y,
    offsetTop: object.offsetTop,
    offsetLeft: object.offsetLeft,
  };
};
